#pragma once
#include <nice2d/predef.h>
#include <nice2d/serializer.h>
#include <nice2d/objectfactory.h>

class DeserializerFactory
{
public:
    static SerializerPointer create(const std::string &name,const PTree &node);

    template<class Target>
    static std::shared_ptr<Target> deserialize(const std::string &name,const PTree &node)
    {
        auto option = node.get_child_optional(name);
        if (option.has_value()) {
            auto value = option.value();
            if(value.empty())
                return nullptr;

            auto current  = value.begin();
            auto deserializer = create(current->first,current->second);
            if (deserializer)
                return std::dynamic_pointer_cast<Target>(deserializer);
        }
        return nullptr;
    }

    template<class Target>
    static std::shared_ptr<Target> deserialize(const PTree &node)
    {
        assert(node.size() == 1);
        auto current = node.begin();
        auto deserializer = create(current->first, current->second);
        if (deserializer)
            return std::dynamic_pointer_cast<Target>(deserializer);
        return nullptr;
    }

    template<class Target>
    static std::shared_ptr<Target> deserialize(const std::string &file)
    {
        boost::property_tree::ptree node;
        boost::property_tree::xml_parser::read_xml(file, node);
        return deserialize<Target>(node);
    }

    template<class Target>
    static std::shared_ptr<Target> deserialize(const std::string &name,const std::string &file)
    {
        boost::property_tree::ptree node;
        boost::property_tree::xml_parser::read_xml(file, node);
        return deserialize<Target>(name, node);
    }
public:
    virtual ~DeserializerFactory();
    virtual SerializerPointer createSerializer(const std::string &name, const PTree &node) = 0;
};

#define DECL_DESERIALIZER_FACTORY_IMPL(type)\
class type##DeserializerFactory : public DeserializerFactory\
{\
public:\
    std::shared_ptr<Serializer> createSerializer(const std::string &name,const PTree &node) override\
    {\
        auto instance = std::make_shared<type>();\
        instance->deserialize(node);\
        return instance;\
    }\
};\
REGISTER_OBJECT_WITH_TYPE(std::string,#type,DeserializerFactory,type##DeserializerFactory)

#define DECLARE_DESERILIZER_FACTORY(target) DECLARE_DESERILIZER_FACTORY_IMPL(target,#target)
#define CREATE_DESERIALIZED_POINTER(var,type) DeserializerFactory::deserialize<type>(#var,node);
